#!/usr/bin/env python3

import argparse
import re
import sys
from pathlib import Path
from typing import Any, Dict, Optional

import yaml
from typing_extensions import TypedDict

Step = Dict[str, Any]


class Script(TypedDict):
    extension: str
    script: str


def extract(step: Step) -> Optional[Script]:
    run = step.get('run')

    # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell
    shell = step.get('shell', 'bash')
    extension = {
        'bash': '.sh',
        'pwsh': '.ps1',
        'python': '.py',
        'sh': '.sh',
        'cmd': '.cmd',
        'powershell': '.ps1',
    }.get(shell)

    is_gh_script = step.get('uses', '').startswith('actions/github-script@')
    gh_script = step.get('with', {}).get('script')

    if run is not None and extension is not None:
        script = {
            'bash': f'#!/usr/bin/env bash\nset -eo pipefail\n{run}',
            'sh': f'#!/usr/bin/env sh\nset -e\n{run}',
        }.get(shell, run)
        return {'extension': extension, 'script': script}
    elif is_gh_script and gh_script is not None:
        return {'extension': '.js', 'script': gh_script}
    else:
        return None


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument('--out', required=True)
    args = parser.parse_args()

    out = Path(args.out)
    if out.exists():
        sys.exit(f'{out} already exists; aborting to avoid overwriting')

    gha_expressions_found = False

    for p in Path('.github/workflows').iterdir():
        with open(p) as f:
            workflow = yaml.safe_load(f)

        for job_name, job in workflow['jobs'].items():
            job_dir = out / p / job_name
            steps = job['steps']
            index_chars = len(str(len(steps) - 1))
            for i, step in enumerate(steps, start=1):
                extracted = extract(step)
                if extracted:
                    script = extracted['script']
                    step_name = step.get('name', '')
                    if '${{' in script:
                        gha_expressions_found = True
                        print(
                            f'{p} job `{job_name}` step {i}: {step_name}',
                            file=sys.stderr
                        )

                    job_dir.mkdir(parents=True, exist_ok=True)

                    sanitized = re.sub(
                        '[^a-zA-Z_]+', '_',
                        f'_{step_name}',
                    ).rstrip('_')
                    extension = extracted['extension']
                    filename = f'{i:0{index_chars}}{sanitized}{extension}'
                    (job_dir / filename).write_text(script)

    if gha_expressions_found:
        sys.exit(
            'Each of the above scripts contains a GitHub Actions '
            '${{ <expression> }} which must be replaced with an `env` variable'
            ' for security reasons.'
        )


if __name__ == '__main__':
    main()
